#include "ProductTestKey.h"
#include "ProductTestUartDataProcess.h"
#include "ProductTestSpk.h"

#define SKIP_TEST_TIME 4

#if CMAKE_INGENIC_T41N
#define DEF_KEY_GPIO_DEV            "/dev/input/event0"
#else
#define DEF_KEY_GPIO_DEV            "/dev/event0"
#endif

typedef enum
{
    KEY_STAT_UP = 0,
    KEY_STAT_DOWN,
} EPerKeyStatus;

Com_s8 key_result[PRODUCT_TEST_RESULT_LEN];

static EPerKeyStatus g_InPer_Key_0_Status = KEY_STAT_UP;
static EPerKeyStatus g_InPer_Key_1_Status = KEY_STAT_UP;
static struct timeval start_time, end_time;

Com_ps8 Ext_ProductTest_Key_Get_Result(void)
{
    return key_result;
}

static double InPer_Key_Difftimeval(struct timeval *old, struct timeval *new)
{
    return (new->tv_sec - old->tv_sec) * 1000 + (new->tv_usec - old->tv_usec) / 1000;
}

void ProductTest_Key_Upload_Info(void)
{
    int i;
    SMsgAVIoctrlUserEvent result;

    printf("upload device uid\n");
    memset(&result, 0, sizeof(result));
    result.event = 100;

    for (i = 0; i < MAX_CLIENT_NUMBER; i++)
    {
        avSendIOCtrl(i, IOTYPE_USER_IPCAM_DEVICE_USER_EVENT_REPORT, (char *)&result, sizeof(SMsgAVIoctrlUserEvent));
    }
}

void ProductTest_Key_Upload_PID(void)
{
    int i;
    int ret;
    SmsgAVIoctrlGetPIDResp resp;

    printf("upload device PID\n");
    memset(&resp, 0, sizeof(resp));

    ret = Ext_InSdkGetInfo_Pid(resp.PID);
    if (ret != DEF_COM_SUCCESS)
    {
        printf("PID is null\n");
        strcpy(resp.PID, "1234567890");
    }

    for (i = 0; i < MAX_CLIENT_NUMBER; i++)
    {
        avSendIOCtrl(i, IOTYPE_USER_IPCAM_GET_PID_RESP,(char *)&resp, sizeof(SMsgAVIoctrlUserEvent));
    }
}

void Ext_ProductTest_Key_Restore_Factory(void)
{
    Ext_InSdkTcpSystem_Cmd("ifconfig wlan0 down");
    Ext_InSdkTcpSystem_Cmd("killall -9 udhcpc wpa_supplicant");
    Ext_InSdkTcpSystem_Cmd("ifconfig wlan0 up");
    Ext_InComFile_Remove(DEF_FLAG_SYNC_TIME_OK);
    Ext_InComFile_JudgeRemove(DEF_TUYA_USER_DP);
    Ext_InComFile_JudgeRemove(DEF_TUYA_USER_DP_BAK);
    Ext_InComFile_JudgeRemove(DEF_TUYA_ENCKEY_DP);
    Ext_InSdkTcpSystem_Cmd("cp /usr/ipcam/bak/dev_config.ini /mnt/config/");
    usleep(100 * 1000);
    Ext_InComFile_JudgeCreat(DEF_FLAG_NO_NETWORK);
    Ext_InComFile_JudgeRemove(DEF_TXT_SAVE_LAST_DATE);
    Ext_InComFile_JudgeRemove(DEF_FILE_SAVE_CONF);
    Ext_InSdkTcpSystem_Cmd("rm /mnt/config/dp_file_flag/*");
    usleep(100 * 1000);
    Ext_InComFile_JudgeCreat(DEF_DP_LIGHT_LED);
}

static int ProductTest_Key_0_Handle(double period)
{
    if (period < 0)
    {
        perror("Error period");
        return -1;
    }
    else if ((period > 0) && (period <= 2))
    {
        strcpy(key_result, PRODUCT_TEST_RESULT_OK);
        ProductTest_Key_Upload_Info();
        ProductTest_Key_Upload_PID();
    }
    else if (period >= SKIP_TEST_TIME)
    {
        static Com_u8 key_reset_flag = DEF_COM_FALSE;

        if (key_reset_flag == DEF_COM_FALSE)
        {
            key_reset_flag = DEF_COM_TRUE;
            StProductTestSpkInfo info;

            info.path = DEF_WAV_DING_DONG;
            info.cnt = 1;

            Ext_ProductTest_Spk_WavPlay_Init(&info);

            /** 关闭MCU端的异常指示灯 **/
            Ext_ProductTest_UartHandle_Set_Warning_Led(0);
            /** 还原出厂设置 **/
            Ext_ProductTest_Key_Restore_Factory();
            sleep(2);
            Ext_InSdkTcpSystem_Cmd("skip_product_test.sh");
            sleep(10);
        }
    }

    return 0;
}

static int ProductTest_Key_0_Level_Detect(struct input_event *event)
{
    double period = 0;
    int trigger_val = 0;

    if (event->value == trigger_val)
    {
        start_time.tv_sec = event->time.tv_sec;
        start_time.tv_usec = event->time.tv_usec;
        g_InPer_Key_0_Status = KEY_STAT_DOWN;
    }
    else if (event->value == (1 - trigger_val))
    {
        period = InPer_Key_Difftimeval(&start_time, &event->time) / 1000;
        ProductTest_Key_0_Handle(period);
        g_InPer_Key_0_Status = KEY_STAT_UP;
        return 0;
    }

    return 1;
}

static int ProductTest_Key_1_Handle(double period)
{
    if (period < 0)
    {
        perror("Error period");
        return -1;
    }

    return 0;
}

static int ProductTest_Key_1_Level_Detect(struct input_event *event)
{
    int trigger_val = 0;
    double period = 0;

    if (event->value == trigger_val)
    {
        start_time.tv_sec = event->time.tv_sec;
        start_time.tv_usec = event->time.tv_usec;
        g_InPer_Key_1_Status = KEY_STAT_DOWN;
    }
    else if (event->value == (1 - trigger_val))
    {
        period = InPer_Key_Difftimeval(&start_time, &event->time) / 1000;
        ProductTest_Key_1_Handle(period);
        g_InPer_Key_1_Status = KEY_STAT_UP;
        return 0;
    }

    return 0;
}

static int ProductTest_Key_Detect(struct input_event *key_event, int key_cnt)
{
    int i = 0;
    int ret = -1;
    struct input_event *event;

    if (key_cnt < (int)sizeof(struct input_event))
    {
        printf("expected %d bytes, got %d\n", (int)sizeof(struct input_event), key_cnt);
        return -1;
    }

    for (i = 0; (i < key_cnt / sizeof(struct input_event)); i++)
    {
        event = (struct input_event *)&key_event[i];
        if (EV_KEY != event->type)
        {
            continue;
        }

        switch (event->code)
        {
        case KEY_0:
            ret = ProductTest_Key_0_Level_Detect(event);
            break;

        case KEY_1:
            ret = ProductTest_Key_1_Level_Detect(event);
            break;

        default:
            printf("%s %s: Error key code!\n", __FILE__, __func__);
            ret = -1;
            break;
        }

        if (!ret)
        {
            break;
        }
    }
    return ret;
}

Com_pvoid ProductTest_Key_Thread(Com_pvoid param)
{
    int ret = 0;
    int gpio_fd;
    int rd = 0;
    fd_set readfds;
    struct input_event key_event[4];
    struct timeval timeout;

    strcpy(key_result, PRODUCT_TEST_RESULT_ERROR);

    if ((gpio_fd = open(DEF_KEY_GPIO_DEV, O_RDONLY)) < 0)
    {
        perror("Open gpio key dev fail");
        return NULL;
    }

    memset(&end_time, 0, sizeof(end_time));

    while (1)
    {
        FD_ZERO(&readfds);
        FD_SET(gpio_fd, &readfds);
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;

        ret = select(FD_SETSIZE, &readfds, (fd_set *)0, (fd_set *)0,
                     (struct timeval *)&timeout);
        if (ret < 0)
        {
        }
        else if (ret == 0)
        {
            /* timeout */
            if (g_InPer_Key_0_Status == KEY_STAT_DOWN)
            {
                double diff_t;
                gettimeofday(&end_time, NULL);
                diff_t = InPer_Key_Difftimeval(&start_time, &end_time) / 1000;
                printf("current sec = %f(s)\n", InPer_Key_Difftimeval(&start_time, &end_time) / 1000);
                if ((InPer_Key_Difftimeval(&start_time, &end_time) / 1000) > SKIP_TEST_TIME)
                {
                    g_InPer_Key_0_Status = KEY_STAT_UP;
                    printf("reset wifi config... \n");
                    ProductTest_Key_0_Handle(diff_t);
                }
            }

            if (g_InPer_Key_1_Status == KEY_STAT_DOWN)
            {
                gettimeofday(&end_time, NULL);
                // printf("end_time's sec= %d, nsec= %d !\n", end_time.tv_sec, end_time.tv_usec);
                printf("pwr off key current sec = %f(s)\n", InPer_Key_Difftimeval(&start_time, &end_time) / 1000);
            }
        }
        else
        {
            if (FD_ISSET(gpio_fd, &readfds))
            {
                rd = read(gpio_fd, key_event, sizeof(struct input_event) * sizeof(key_event));
                ProductTest_Key_Detect(key_event, rd);
            }
        }
    }

    return NULL;
}

void Ext_ProductTest_Key_Init(void)
{
    pthread_t key_id;

    pthread_create(&key_id, NULL, ProductTest_Key_Thread, NULL);
    pthread_detach(key_id);
}
